/**
 * File: NodePartialMatchCutoff.java
 * Created by: mhaimel
 * Created on: Mar 30, 2010
 * CVS:  $Id: NodePartialMatchCutoff.java 1.0 Mar 30, 2010 9:11:39 AM mhaimel Exp $
 */
package uk.ac.ebi.curtain.model.graph.curtain.filter;

import java.util.Collection;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicReference;

import uk.ac.ebi.curtain.model.graph.Arc;
import uk.ac.ebi.curtain.model.graph.Graph;
import uk.ac.ebi.curtain.model.graph.Node;
import uk.ac.ebi.curtain.model.graph.NodeEdge;
import uk.ac.ebi.curtain.model.graph.GraphAccess.TouchEach;
import uk.ac.ebi.curtain.model.graph.curtain.CategoryReadInfo;
import uk.ac.ebi.curtain.model.graph.curtain.ContigInfo;
import uk.ac.ebi.curtain.model.graph.curtain.ReadWrapper;

/**
 * @author mhaimel
 *
 */
public class NodePartialMatchCutoff implements TouchEach<Node<ContigInfo, ReadWrapper>>  {

	private final AtomicIntegerArray cutoff;
	private final boolean maxEdge;
	private final AtomicReference<Graph<ContigInfo, ReadWrapper>> graph;

	/**
	 * @param cutoffCategory
	 * @param isMaxCutoff
	 */
	public NodePartialMatchCutoff(int[] cutoffCategory, boolean isMaxCutoff, Graph<ContigInfo, ReadWrapper> graph) {
		this.cutoff = new AtomicIntegerArray(cutoffCategory);
		this.maxEdge = isMaxCutoff;
		this.graph = new AtomicReference<Graph<ContigInfo, ReadWrapper>>(graph);
	}

	
	@Override
	public void touch(Node<ContigInfo, ReadWrapper> node) {
		int categories = getCategories();
		NodeEdge[] values = NodeEdge.values();
		for(int cat = 0; cat < categories; ++cat){
			for(NodeEdge edge : values){
				if(isOutOfRange(cat, node,getCutoff(cat), isMaxCutoff(), edge)){
					setPartialFlag(node,cat,edge);
					if(isMaxCutoff()){
						removeArcs(node,cat,edge);
					} 
				}
			}
		}
	}
	
	private void setPartialFlag(Node<ContigInfo, ReadWrapper> node, int cat,NodeEdge edge) {
		ContigInfo info = node.getValue();
		info.setPartialFlag(cat, edge);
	}

	private void removeArcs(Node<ContigInfo, ReadWrapper> node, int cat,NodeEdge edge) {
		Collection<Arc<ContigInfo, ReadWrapper>> arcColl = node.getArcs(edge);
		
		for(Arc<ContigInfo, ReadWrapper> arc : arcColl){
			CategoryReadInfo val = arc.getValue().getInfo(cat);
			if(null != val){
				// remove info
				arc.getValue().forceSetCategoryReadInfo(cat, null);
			}
			if(!arc.getValue().hasAnyInfo()){
				getGraph().removeArc(arc);
			}
		}
	}

	private Graph<ContigInfo, ReadWrapper> getGraph() {
		return this.graph.get();
	}


	protected boolean isOutOfRange(int cat, Node<ContigInfo, ReadWrapper> node,int cutoff, boolean isMaxCutoff, NodeEdge edge) {
		Integer partial = node.getValue().getPartial(cat,edge);	
		return isMaxCutoff?partial > cutoff:partial < cutoff;
	}
	
	protected boolean isMaxCutoff() {
		return maxEdge;
	}

	protected int getCutoff(int cat) {
		return this.cutoff.get(cat);
	}
	protected int getCategories() {
		return cutoff.length();
	}

}
